﻿using System;
using System.Collections;
using OpenTK;

namespace Painter3D.RenderSys
{
    /// <summary>
    /// 渲染管线基础类
    /// </summary>
    abstract class RenderPiple
    {
        static public RenderPiple renderPiple;
        private Stack matrixStack = new Stack();

        protected RenderPiple()
        {
            renderPiple = this;
        }

        /// <summary>
        /// 根据设置的渲染管线完成渲染
        /// </summary>
        public abstract void RenderOut();

        /// <summary>
        /// 使用摄像机渲染符合mask的物体
        /// </summary>
        /// <param name="camera">摄像机</param>
        /// <param name="mask">mask</param>
        protected void RenderByCmareaWithMask(Camera camera, uint mask)
        {
            if (camera == null)
            {
                throw new ArgumentNullException(nameof(camera));
            }
            //设置渲染窗口
            camera.ApplyViewRect();
            //设置全局变量值
            SetUPUniformBuffer(camera);
            //逐个渲染,同时完成世界矩阵的计算
            matrixStack.Clear();
            matrixStack.Push(Matrix4.Identity);
            int lastLayer = -1;
            Transform.WorldTransform.LoopTreeWithF((transform, layer) =>
            {
                //处理矩阵堆栈.默认只可能多一层深度
                for (int i = 0; i < lastLayer - layer + 1; i++)
                {
                    matrixStack.Pop();
                }
                matrixStack.Push(transform.Mat * (Matrix4)matrixStack.Peek());
                Render render = transform.GetComponent<Render>();
                if (render != null && render.layer.InMask(mask))
                {
                    render.RenderOut((Matrix4)matrixStack.Peek());
                }
                lastLayer = layer;
                return false;
            }, 0, true);
        }

        /// <summary>
        /// 使用摄像机渲染指定的物体
        /// </summary>
        /// <param name="camera">摄像机</param>
        /// <param name="renderableObject">可渲染对象，其节点必须挂载render组件</param>
        protected void RenderByCamera(Camera camera, Transform renderableObject)
        {
            if (camera == null)
            {
                throw new ArgumentNullException(nameof(camera));
            }
            Render render = renderableObject.GetComponent<Render>();
            if (render == null)
            {
                throw new Exception("输入的节点本身不包含渲染器组件");
            }
            camera.ApplyViewRect();
            //设置全局变量值
            SetUPUniformBuffer(camera);

            render.RenderOut(renderableObject.GetGlobalMat());
        }

        /// <summary>
        /// 使用摄像机渲染指定的物体及其可渲染的子对象
        /// </summary>
        /// <param name="camera">摄像机</param>
        /// <param name="renderableObject">可渲染对象</param>
        /// <param name="mask">mask</param>
        protected void RenderFamilyByCameraWithMask(Camera camera, Transform renderableObject, uint mask)
        {
            if (camera == null)
            {
                throw new ArgumentNullException(nameof(camera));
            }
            camera.ApplyViewRect();
            //设置全局变量值
            SetUPUniformBuffer(camera);
            //准备矩阵堆栈
            matrixStack.Clear();
            matrixStack.Push(Matrix4.Identity);
            int lastLayer = -1;
            renderableObject.LoopTreeWithF((transform, layer) =>
            {
                //处理矩阵堆栈.默认只可能多一层深度
                for (int i = 0; i < lastLayer - layer + 1; i++)
                {
                    matrixStack.Pop();
                }
                matrixStack.Push(transform.Mat * (Matrix4)matrixStack.Peek());
                Render render = transform.GetComponent<Render>();
                if (render != null && render.layer.InMask(mask))
                {
                    render.RenderOut((Matrix4)matrixStack.Peek());
                }
                lastLayer = layer;
                return false;
            }, 0, true);
        }

        protected void RenderSkyBox(Camera camera, Transform skybox)
        {
            if (camera == null)
            {
                throw new ArgumentNullException(nameof(camera));
            }
            Render render = skybox.GetComponent<Render>();
            if (render == null)
            {
                throw new Exception("输入的节点本身不包含渲染器组件,请确认其为天空盒");
            }
            camera.ApplyViewRect();
            Matrix4 matrix = new Matrix4(new Matrix3(camera.GetViewMat())) * camera.GetProjectMat();
            UniformBlock.SetValue("SetingBlock", "cameraMat", matrix);
            render.RenderOut(skybox.Mat);
        }

        /// <summary>
        /// 设置全局变量UBO
        /// </summary>
        /// <param name="camera">相关摄像机</param>
        static public void SetUPUniformBuffer(Camera camera)
        {
            UniformBlock.SetValue("SetingBlock", "cameraMat", camera.GetCameraMat());
            UniformBlock.SetValue("LightBlock", "viewPos", camera.Transform.position);
        }
    }
}
